﻿namespace CodeBetter.Extensions.Tests
{
   using System.Collections;
   using System.Collections.Generic;
   using System.Collections.ObjectModel;
   using NUnit.Framework;
   using System.Collections.Specialized;
   using System.Data;
using System.ComponentModel;

   [TestFixture]
   public class IEnumerableTests
   {
      [Test]
      public void Each()
      {
         int[] list = new[] {1, 2, 3, 4};
         int[] seen = new int[4];
         int counter = 0;
         list.Each(i => seen[counter++] = i);         
         Assert.AreEqual(list, seen);
      }
      [Test, ExpectedException("System.ArgumentNullException")]
      public void Each_ThrowsExceptionForNullAction()
      {
         new[] {0}.Each(null);
         Assert.Fail();
      }

      [Test]
      public void TrueForAll()
      {         
         Assert.IsTrue(new[] { 1, 2, 3, 4 }.TrueForAll(i => i / 1 == i));
         Assert.IsFalse(new[] { 1, 2, 3, 4 }.TrueForAll(i => i / 1 == 0));
      }
      [Test, ExpectedException("System.ArgumentNullException")]
      public void TrueForAll_ThrowsExceptionForNullAction()
      {
         new[] { 0 }.TrueForAll(null);
         Assert.Fail();
      }

      [Test]
      public void Find()
      {
         var values = new ReadOnlyCollection<int>(new[]{1,2,3,4});
         Assert.AreEqual(2, values.Find(i => i == 2));
      }
      [Test, ExpectedException("System.ArgumentNullException")]
      public void Find_ThrowsExceptionForNullPredicate()
      {
         var values = new ReadOnlyCollection<int>(new[] { 1, 2, 3, 4 });
         Assert.AreEqual(2, values.Find(null));         
      }
      [Test]
      public void Find_ReturnsNullIfNotFound()
      {
         var values = new ReadOnlyCollection<int>(new[] { 1, 2, 3, 4 });
         Assert.AreEqual(0, values.Find(i => i == 10));

         var values2 = new ReadOnlyCollection<string>(new[] { "a" });
         Assert.AreEqual(null, values2.Find(i => i == "b"));
      }     

      [Test]
      public void FindAll()
      {
         var values = new ReadOnlyCollection<int>(new[] { 1, 2, 3, 4 });
         Assert.AreEqual(new[]{2,4}, values.FindAll(i => i % 2 == 0).ToArray());
      }
      [Test, ExpectedException("System.ArgumentNullException")]
      public void FindAll_ThrowsExceptionForNullPredicate()
      {
         var values = new ReadOnlyCollection<int>(new[] { 1, 2, 3, 4 });
         Assert.AreEqual(2, values.FindAll(null));
      }

      private class EnumarableAndListSource : IEnumerable, IListSource
      {
         #region IListSource Members

         public bool ContainsListCollection
         {
            get { throw new System.NotImplementedException(); }
         }

         public IList GetList()
         {
            throw new System.NotImplementedException();
         }

         #endregion

         #region IEnumerable Members

         public IEnumerator GetEnumerator()
         {
            yield break;
         }

         #endregion
      }

      [Test]
      public void IEnumerable_IsNullOrEmpty()
      {
         // Array
         string[] test = null;
         Assert.AreEqual(true, test.IsNullOrEmpty());
         test = new string[] { };
         Assert.AreEqual(true, test.IsNullOrEmpty());
         test = new string[] { "one" };
         Assert.AreEqual(false, test.IsNullOrEmpty());
         // ICollection
         Queue testqueue = null;
         Assert.AreEqual(true, testqueue.IsNullOrEmpty());
         testqueue = new Queue();
         Assert.AreEqual(true, testqueue.IsNullOrEmpty());
         testqueue.Enqueue("test");
         Assert.AreEqual(false, testqueue.IsNullOrEmpty());
         // ICollection<T>
         Queue<string> testqueuet = null;
         Assert.AreEqual(true, testqueuet.IsNullOrEmpty());
         testqueuet = new Queue<string>();
         Assert.AreEqual(true, testqueuet.IsNullOrEmpty());
         testqueuet.Enqueue("test");
         Assert.AreEqual(false, testqueuet.IsNullOrEmpty());
         // IList
         StringCollection testlist = null;
         Assert.AreEqual(true, testlist.IsNullOrEmpty());
         testlist = new StringCollection();
         Assert.AreEqual(true, testlist.IsNullOrEmpty());
         testlist.Add("test");
         Assert.AreEqual(false, testlist.IsNullOrEmpty());
         // IList<T>
         List<string> testlistt = null;
         Assert.AreEqual(true, testlistt.IsNullOrEmpty());
         testlistt = new List<string>();
         Assert.AreEqual(true, testlistt.IsNullOrEmpty());
         testlistt.Add("test");
         Assert.AreEqual(false, testlistt.IsNullOrEmpty());
         // DataTable
         DataTable testtable = null;
         Assert.AreEqual(true, testtable.IsNullOrEmpty());
         testtable = new DataTable();
         Assert.AreEqual(true, testtable.IsNullOrEmpty());
         testtable.Columns.Add();
         testtable.Columns.Add();
         testtable.Rows.Add(new string[] { "col1", "col2" });
         Assert.AreEqual(false, testtable.IsNullOrEmpty());
         // implements a lot of interfaces
         ReadOnlyCollection<string> testcoll = null;
         Assert.AreEqual(true, testcoll.IsNullOrEmpty());
         testcoll = new ReadOnlyCollection<string>(new string[] { });
         Assert.AreEqual(true, testcoll.IsNullOrEmpty());
         testcoll = new ReadOnlyCollection<string>(new string[] { "test" });
         Assert.AreEqual(false, testcoll.IsNullOrEmpty());
         // string
         string teststring = null;
         Assert.AreEqual(true, teststring.IsNullOrEmpty());
         teststring = "";
         Assert.AreEqual(true, teststring.IsNullOrEmpty());
         teststring = "test";
         Assert.AreEqual(false, teststring.IsNullOrEmpty());

         // should also work on IDictionary, IDictionary<K, T>

         // double implemented interface (needs disambiguation)
         EnumarableAndListSource tst = new EnumarableAndListSource();
         Assert.AreEqual(true, (tst as IEnumerable).IsNullOrEmpty());
      }
   }
}
